#include <54func.h>

#define NETDISK_LOG_ERR //todo
// 1.0
// 用于客户端向服务区接收数据

//int recvFile(int sockfd)
//{
//    char filename[4096] = {0};
//    recv(sockfd,filename,sizeof(filename),0);//读取传送的文件名
//    int fd = open(filename,O_RDWR|O_CREAT);//根据文件名，创建文件
//    ERROR_CHECK(fd,-1,"open");
//    char buf[1000] = {0};
//    ssize_t sret = recv(sockfd,buf,sizeof(buf),0); //从socket中读文件内容
//    write(sockfd,buf,sret);//把读取的文件内容写道文件内
//    return 0;
//}

// 2.0 小文件发送
//typedef struct train_s{
//    int length;
//    char data[1000];
//}train_t;
//int recvFile(int sockfd)
//{
//    char filename[4096] = {0};
//    train_t train;
//    //先收火车头，以知道火车车厢的实际长度
//    recv(sockfd,&train.length,sizeof(train.length),0);//火车头
//    recv(sockfd,train.data,train.length,0);//火车车厢
//    memcpy(filename,train.data,train.leingth);
//
//    int fd = open(filename,O_CREAT|O_RDWR,0666);
//    ERROR_CHECK(fd,-1,"open");
//    recv(sockfd,&train.length,sizeof(train.length),0);
//    recv(sockfd,train.data,train.length,0);
//    write(fd,train.data,train.length);
//    close(fd);
//    return 0;
//
//}

// 3.0 大文件发送
//typedef struct train_s{
//    int length;
//    char data[1000];
//}train_t;
//int recvFile(int sockfd)
//{
//    train_t train;
//    char filename[4096];
//    recv(sockfd,&train.length,sizeof(train.length),MSG_WAITALL);
//    recv(sockfd,train.data,train.length,MSG_WAITALL);
//    memcpy(filename,train.data,train.length);
//
//    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
//    while(1)
//    {
//        recv(sockfd,&train.length,sizeof(train.length),MSG_WAITALL);
//        if(train.length != 1000)
//        {
//            printf("train.length = %d\n",train.length);
//        }
//        if(train.length == 0)
//        {
//            break;
//        }
//        recv(sockfd,train.data,train.length,MSG_WAITALL);
//        write(fd,train.data,train.length);
//       // // 如果读取的火车头数据长度为0，则数据读完，
//       // if(sret == 0)
//       // {
//       //     break;
//       // }
//    }
//
//    close(fd);
//    return 0;
//}

// v4.0 进度条显示
typedef struct train_s{
    int length;
    char data[1000];
}train_t;
int recvFile(int sockfd)
{
    train_t train;
    char filename[4096];
    recv(sockfd,&train.length,sizeof(train.length),MSG_WAITALL);
    recv(sockfd,train.data,train.length,MSG_WAITALL);
    memcpy(filename,train.data,train.length);

    // 接收文件长度
    off_t filesize;
    recv(sockfd,&train.length,sizeof(train.length),MSG_WAITALL);
    recv(sockfd,train.data,train.length,MSG_WAITALL);
    memcpy(&filesize,train.data,train.length);
    printf("filesize = %ld\n",filesize);
    off_t cursize = 0;//off_t：表示文件的偏移量
    off_t lastsize = 0;// 上次printf的时候，文件的大小
    off_t slice = filesize/10000;// 若是前后两次文件大小打印的差距若是不到万分之一，则没有必要更新i
    
    int fd = open(filename,O_RDWR|O_CREAT|O_TRUNC,0666);
    while(1)
    {
        recv(sockfd,&train.length,sizeof(train.length),MSG_WAITALL);
        if(train.length != 1000)
        {
            printf("train.length = %d\n",train.length);
        }
        if(train.length == 0)
        {
            break;
        }
        cursize += train.length;
        recv(sockfd,train.data,train.length,MSG_WAITALL);
        write(fd,train.data,train.length);
       // // 如果读取的火车头数据长度为0，则数据读完，
       // if(sret == 0)
       // {
       //     break;
       // }
        if(cursize - lastsize > slice)
        {
            // 若是这次打印相较于上次打印差距超过百分之0.0001，则打印：w:w
            printf("%5.2lf%%\r",cursize*100.0/filesize);
            fflush(stdout);
            lastsize = cursize;
        }
    }
    printf("100%%\n");
    close(fd);
    return 0;
}

// 解析输入的命令行字符串（buf）,提取其中的命令（cmd）和参数（arg）   cd/ls/mkdir/pwd 
int analyse_command(char *buf,char *cmd,char *arg)
{
    int idx_buf = 0,idx_cmd = 0,idx_arg = 0;
    
    // 跳过所有的签到空格和换行符
    while(buf[idx_buf] == ' ' || buf[idx_buf] == '\n')
    {
            ++idx_buf;
    }

    // 提取命令部分：从buf中提取连续的字符字母，并将其存储再cmd中，提取完以后，将cmd的末尾加上字符串终止符‘\0’
    while(isalpha(buf[idx_buf])) // isalpha：用于检查给定的字符是否为字母 是返回0，否返回1
    {
        cmd[idx_cmd++] = buf[idx_buf++];
    }
    cmd[idx_cmd] = '\0';

    // 验证命令是否有效：检查提取的命令是否是一下支持的命令之一
    if(strcmp(cmd,"ls") != 0
       && strcmp(cmd,"cd") !=0
       && strcmp(cmd,"puts") != 0
       && strcmp(cmd,"gets") !=0
       && strcmp(cmd,"remove") !=0
       && strcmp(cmd,"pwd") !=0
       && strcmp(cmd,"mkdir") !=0){
        return -1;
    }

    // 提取参数部分：
    while(buf[idx_buf] == ' ' && idx_buf <= strlen(buf)) // 跳过命令后的所有空格
    {
        ++idx_buf;
    }
    // 再arg的开头添加一个空格
    arg[idx_arg++] = ' ';// 执行过程：arg[idx_arg] = '';->idx_arg++
    // 将剩余的字符串（即参数部分）复制到arg中
    while(buf[idx_buf])
    {
        arg[idx_arg++] = buf[idx_buf++];//这段代码从arg为1开始执行
    }
    // 最后将arg的末尾的空格替换为字符串终止符‘\0’
    arg[idx_arg -1] = '\0';

    return 0;
// e.g. 
//执行过程
//       跳过前导空格：buf 从 "cd" 开始。
//       提取命令：cmd = "cd"。
//       验证命令："cd" 是支持的命令，继续。
//       提取参数：
//               跳过空格，buf 从 "/home/user" 开始。
//               arg = " /home/user"（注意开头多了一个空格）。
//               最后将 arg 的末尾空格替换为 '\0'，最终 arg = "/home/user"。
//输出
//    cmd = "cd"
//    arg = "/home/user"
//    返回值 = 0

     
}

int main(int argc,char * argv[])
{
    // ./ client 192.168.187.128 1234
    ARGS_CHECK(argc,3);
    int sockfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in serveraddr;
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr = inet_addr(argv[1]);
    
    int ret = connect(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
    ERROR_CHECK(ret,-1,"connect");
    
    
    char login_name[1024] = {0};
    char login_password[1024] = {0};
    printf("请输入用户名及密码：\n");
    scanf("%s %s",login_name,login_password);
    // 将客户端输入的用户及密码发送给服务器端
    send(sockfd,login_name,sizeof(login_name),0);
    send(sockfd,login_password,sizeof(login_password),0);

 char buf[4096], cmd[4096], arg[4096];
    while(1){
        bzero(buf, sizeof(buf));
        bzero(cmd, sizeof(cmd));
        bzero(arg, sizeof(arg));

        printf("---------------------------------------\n");
        fgets(buf, sizeof(buf), stdin);
        printf("strbuf = %ld, buf = %s\n", strlen(buf), buf);
        int ret = analyse_command(buf, cmd, arg);

       // printf("After analyse:\n");
       // printf("%s\n", ret == 0 ? "legal" : "illegal");
       // printf("cmd_len = %ld, cmd = %s\n", strlen(cmd), cmd);
       // printf("arg_len = %ld, arg = %s\n", strlen(arg), arg);

        printf("\nBefore send:\n");
        if(ret == -1){
            printf("Invalid command!\n");
            continue;
        }
        else{
            train_t t_cmd, t_arg;
            bzero(&t_cmd, sizeof(train_t));
            bzero(&t_arg, sizeof(train_t));

            t_cmd.length = strlen(cmd);
            printf("t_cmd.length = %d\n", t_cmd.length);
            strncpy(t_cmd.data, cmd, t_cmd.length);
            t_arg.length = strlen(arg);
            printf("t_arg.length = %d\n", t_arg.length);
            strncpy(t_arg.data, arg, t_arg.length);

            //send(sockfd, &t_cmd.length, sizeof(t_cmd.length), MSG_NOSIGNAL);
            //send(sockfd, &t_cmd.data, t_cmd.length, MSG_NOSIGNAL);
            //send(sockfd, &t_arg.length, sizeof(t_arg.length), MSG_NOSIGNAL);
            //send(sockfd, &t_arg.data, t_arg.length, MSG_NOSIGNAL);
            send(sockfd, &t_cmd, sizeof(t_cmd.length) + t_cmd.length, MSG_NOSIGNAL);
            send(sockfd, &t_arg, sizeof(t_arg.length) + t_arg.length, MSG_NOSIGNAL);

            if(strncmp(t_cmd.data, "gets", 4) == 0){
                recvFile(sockfd);
            }
            else if(strncmp(t_cmd.data, "puts", 4) == 0){
                //sendFile(sockfd);
                recvFile(sockfd);
            }
            else{
                char ret[4096] = {0};
                fd_set rdset;
                while(1){
                    bzero(ret, sizeof(ret));
                    FD_ZERO(&rdset);
                    FD_SET(sockfd, &rdset);
                    if(FD_ISSET(sockfd, &rdset)){
                        bzero(buf, sizeof(buf));
                        //recvn(sockfd, buf,sizeof(buf));
                        sleep(1);
                        ssize_t sret = recv(sockfd, buf, sizeof(buf), 0);
                        printf("buf = %s\n", buf);
                        break;
                    }
                }
            }
        }
    }
    
    return 0;
}


